class HYEventBus {
  constructor() {

  }

  /**
   * 监听特定事件，当该事件被触发时，会调用指定的处理函数
   * @param {string} eventName - 事件名称
   * @param {function} eventCallback - 处理函数
   * @param {*} thisArg 
   */
  on(eventName, eventCallback, thisArg) {
    // 从事件总线中获取指定事件的处理函数数组（handlers）
    let handlers = this.eventBus[eventName];

    // 如果指定事件名的处理函数数组不存在，则创建一个空数组
    if (!handlers) {
      handlers = [];
      this.eventBus[eventName] = handlers;
    }

    // 将新的处理函数和对应的this上下文作为对象添加到事件的处理函数数组中
    handlers.push({
      eventCallback,
      thisArg
    })

  }

  /**
   * 发射特定事件，通知所有订阅了该事件的监听器
   * @param {string} eventName - 事件名称
   * @param  {...any} payload  - 可选参数，事件数据
   */
  emit(eventName, ...payload) {
    // 获取指定事件名的处理函数数组
    const handlers = this.eventBus[eventName];

    // 如果没有处理函数数组，则直接返回
    if (!handlers) return;

    // 遍历所有的处理函数，并调用它们，传递payload参数
    handlers.forEach(handler => {
      // 使用apply方法，确保处理函数的上下文是注册时传入的thisArg
      handler.eventCallback.apply(handler.thisArg, payload);
    })

  }

  /**
   * 取消对某个事件的监听
   * @param {string} eventName - 事件名称
   * @param {function} eventCallback - 要取消的处理函数
   */
  off(eventName, eventCallback) {
    // 获取指定事件名的处理函数数组
    const handlers = this.eventBus[eventName];

    // 如果指定事件名没有处理函数数组，则直接返回
    if (!handlers) return;

    // 复制当前的处理函数数组，防止遍历过程中发生数组的修改(边界处理)
    const newHandlers = [...handlers];

    // 遍历所有的处理函数
    for (let i = 0; i < newHandlers.length; i++) {
      const handler = newHandlers[i];
      // 如果找到指定的处理函数，则从原数组中删除
      if (handler.eventCallback === eventCallback) {
        const index = handlers.indexOf(handler);
        handlers.splice(index, 1);
      }
    }

  }
}

const eventBus = new HYEventBus();


/**
 * @example
 *
 * ```js
 * // main.js
 * eventBus.on('abc', function () {
 *  console.log("监听abc1", this);
 * }, { name: 'why' });
 * 
 * const handleCallback = function () {
 *  console.log("监听abc2", this)
 * }
 * eventBus.on("abc", handleCallback, { name: "why" });
 * 
 * // utils.js
 * eventBus.emit('abc', 123);
 * 
 * // 移除监听
 * eventBus.off("abc", handleCallback)
 * eventBus.emit("abc", 123)
 * 
 * ```
 * 
 */